from django.db import transaction
from rest_framework.authentication import BasicAuthentication, TokenAuthentication
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.exceptions import NotFound, ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response

from api.serializers.cart_serializer import CartAddSerializer, CartUpdateSerializer
from app.models import Cart, ProductSpec


def cart_to_dict(cart):
    return {
        "cart_id": cart.id,
        "spec_id": cart.spec.id,
        "spec_name": cart.spec.name,
        "product_id": cart.spec.product.id,
        "product_name": cart.spec.product.name,
        "product_image": cart.spec.product.image_url,
        "amount": cart.amount,
        "price": cart.spec.price,
        "unit": cart.spec.unit,
        'discount': cart.spec.discount,
        'deposit': cart.spec.deposit,
        'deposit_desc': cart.spec.deposit_desc
    }


def cart_to_response_data(cart, detail):
    return {
        "detail": detail,
        "cart": cart_to_dict(cart)
    }


@api_view(['GET'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def get_user_cart(request: Request):
    user = request.user
    queryset = Cart.objects.filter(user=user)
    return Response(data=[cart_to_dict(cart) for cart in queryset])


@api_view(['POST'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def add_user_cart(request: Request):
    data = {
        'user': request.user.id,
    }
    data.update(request.data)
    serializer = CartAddSerializer(data=data)
    if serializer.is_valid():
        amount = serializer.data['amount']
        spec_id = serializer.data['spec']
        with transaction.atomic():
            try:
                cart = Cart.objects.select_for_update().get(user=request.user, spec=spec_id)
                cart.amount += amount
            except Cart.DoesNotExist:
                spec = ProductSpec.objects.get(id=spec_id)
                cart = Cart(user=request.user, spec=spec, amount=amount)
            cart.save()

        return Response(data=cart_to_response_data(cart=cart, detail=u"添加成功"))
    else:
        raise ValidationError(serializer.errors)


@api_view(['DELETE'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def delete_user_cart(request: Request):
    if "carts" not in request.data:
        raise ValidationError(detail=u"carts字段不能为空")

    cart_ids = [str(cart['cart_id']) for cart in request.data['carts']]
    cart_ids_str = ','.join(cart_ids)
    try:
        Cart.objects.filter(user=request.user) \
            .extra(where=['id in (' + cart_ids_str + ')']).delete()
    except Cart.DoesNotExist:
        raise CartNotFound()
    return Response(data={"detail": u'删除成功'})


@api_view(['PUT'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def update_user_cart(request: Request):
    serializer = CartUpdateSerializer(data=request.data)
    if serializer.is_valid():
        amount = serializer.data['amount']
        spec_id = serializer.data['spec']
        try:
            cart = Cart.objects.get(spec=spec_id, user=request.user)
        except:
            raise CartNotFound()
        if amount == 0:
            cart.delete()
        else:
            cart.amount = amount
            cart.save()

        return Response(data=cart_to_response_data(cart=cart, detail=u'更新成功'))
    else:
        raise ValidationError(serializer.errors)


class CartNotFound(NotFound):
    default_detail = u'商品不在购物车内'
